// Diplomat.cs
//
// Copyright (c) 2007 Mike Strobel
//
// This source code is subject to the terms of the Microsoft Reciprocal License (Ms-RL).
// For details, see <http://www.opensource.org/licenses/ms-rl.html>.
//
// All other rights reserved.

using System;
using System.Linq;

using Supremacy.Collections;
using Supremacy.Economy;
using Supremacy.Entities;
using Supremacy.Game;

namespace Supremacy.Diplomacy
{
    [Serializable]
    public class Diplomat
    {
        private readonly int _ownerId;
        private readonly CivilizationKeyedMap<ValuePair<Alien, IDiplomacyData>> _aliens;

        public int OwnerID
        {
            get { return _ownerId; }
        }

        public Civilization Owner
        {
            get { return GameContext.Current.Civilizations[_ownerId]; }
        }

        public Treasury OwnerTreasury
        {
            get { return GameContext.Current.CivilizationManagers[_ownerId].Treasury; }
        }

        public ResourcePool OwnerResources
        {
            get { return GameContext.Current.CivilizationManagers[_ownerId].Resources; }
        }

        public IDiplomacyData GetData(Civilization civilization)
        {
            if (civilization == null)
                throw new ArgumentNullException("civilization");
            EnsureAlien(civilization);
            return _aliens[civilization.CivID].Second;
        }

        public IDiplomacyDataExtended GetExtendedData(Civilization civilization)
        {
            if (civilization == null)
                throw new ArgumentNullException("civilization");
            return GameContext.Current.DiplomacyData[_ownerId, civilization.CivID];
        }

        public Alien GetAlien(Civilization civilization)
        {
            if (civilization == null)
                throw new ArgumentNullException("civilization");
            EnsureAlien(civilization);
            return _aliens[civilization.CivID].First;
        }

        public Diplomat(Civilization owner)
        {
            if (owner == null)
                throw new ArgumentNullException("owner");
            _ownerId = owner.CivID;
            _aliens = new CivilizationKeyedMap<ValuePair<Alien, IDiplomacyData>>(o => o.First.CivilizationID);
        }

        protected void EnsureAlien(Civilization civilization)
        {
            if (civilization == null)
                throw new ArgumentNullException("civilization");
            if (!_aliens.Contains(civilization.CivID))
            {
                _aliens.Add(
                    new ValuePair<Alien, IDiplomacyData>(
                        new Alien(Owner, civilization),
                        GameContext.Current.DiplomacyData[OwnerID, civilization.CivID].BaseData));
            }
        }

        public void EnsureEnvoys()
        {
            foreach (Civilization civ in GameContext.Current.Civilizations)
            {
                EnsureAlien(civ);
            }
        }

        public bool CanAfford(IProposal proposal)
        {
            if (proposal == null)
                throw new ArgumentNullException("proposal");

            foreach (IClause clause in proposal.Clauses)
            {
                switch (clause.ClauseType)
                {
                    case ClauseType.OfferGiveCredits:
                        if (proposal.Sender == this.Owner)
                        {
                            if (OwnerTreasury.CurrentLevel < clause.GetData<int>())
                                return false;
                        }
                        break;

                    case ClauseType.RequestGiveCredits:
                        if (proposal.Recipient == this.Owner)
                        {
                            if (OwnerTreasury.CurrentLevel < clause.GetData<int>())
                                return false;
                        }
                        break;

                    case ClauseType.OfferGiveResources:
                        if (proposal.Sender == this.Owner)
                        {
                            ResourceValueCollection resources = clause.GetData<ResourceValueCollection>();
                            if ((resources != null) && !OwnerResources.MeetsOrExceeds(resources))
                                return false;
                        }
                        break;

                    case ClauseType.RequestGiveResources:
                        if (proposal.Recipient == this.Owner)
                        {
                            ResourceValueCollection resources = clause.GetData<ResourceValueCollection>();
                            if ((resources != null) && !OwnerResources.MeetsOrExceeds(resources))
                                return false;
                        }
                        break;

                }
            }
            return true;
        }

        public static Diplomat Get(Civilization owner)
        {
            return GameContext.Current.Diplomats[owner];
        }

        public static Diplomat Get(GameObjectID ownerId)
        {
            return GameContext.Current.Diplomats[ownerId];
        }

        public static Diplomat Get(string ownerKey)
        {
            return GameContext.Current.Diplomats[ownerKey];
        }
    }
}